package org.springframework.aop.aspectj;

import org.aspectj.weaver.tools.PointcutExpression;
import org.aspectj.weaver.tools.PointcutParser;
import org.aspectj.weaver.tools.PointcutPrimitive;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;

import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;

/**
 * 支持AspectJ切点表达式的PointCut实现，简单实现仅支持execution函数。
 */
public class AspectJExpressionPointcut implements Pointcut, MethodMatcher, ClassFilter {
    /**
     * 记录支持的切点的分类的集合 简单实现仅支持execution
     */
    private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet<>();

    //只添加execution的切点表达式类型
    static {
        SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION);
    }

    //封装好的切点表达式对象
    private final PointcutExpression pointcutExpression;

    //构造器 创建对象的时候需要传递切点表达式
    public AspectJExpressionPointcut(String expression) {
        //获取切点的解析器
        PointcutParser pointcutParser = PointcutParser
                .getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(SUPPORTED_PRIMITIVES, this.getClass().getClassLoader());
        //解析切点表达式的字符串为切点表达式对象
        pointcutExpression = pointcutParser.parsePointcutExpression(expression);
    }

    /**
     * 判断Aspectj切点是否匹配指定的类
     * @param clazz
     * @return
     */
    @Override
    public boolean matches(Class<?> clazz) {
        return pointcutExpression.couldMatchJoinPointsInType(clazz);
    }

    /**
     * 判断Aspectj切点是否匹配指定类里的方法
     * @param method
     * @param targetClass
     * @return
     */
    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        return pointcutExpression.matchesMethodExecution(method).alwaysMatches();
    }

    @Override
    public ClassFilter getClassFilter() {
        return this;
    }

    @Override
    public MethodMatcher getMethodMatcher() {
        return this;
    }
}
